﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YArchitech.DataModel;
using YArchitech.Revit;

namespace YArchitech.Plumbing
{
	public class SectorLaySprinkler
	{
		public SectorLaySprinkler(Autodesk.Revit.DB.Document document)
		{
			this.doc = document;
		}

		public bool CheckPoints(XYZ startPnt, XYZ endPnt, XYZ onPnt, ref string creatMSG)
		{
			bool result = true;
			this.SetPointZValue(ref startPnt, this.GetActiveViewZeroLevle());
			this.SetPointZValue(ref endPnt, this.GetActiveViewZeroLevle());
			this.SetPointZValue(ref onPnt, this.GetActiveViewZeroLevle());
			this.sPoint = startPnt;
			this.ePoint = endPnt;
			this.onPoint = onPnt;
			try
			{
				if (startPnt.IsAlmostEqualTo(endPnt, 0.001) || endPnt.IsAlmostEqualTo(onPnt, 0.001) || startPnt.IsAlmostEqualTo(onPnt, 0.001))
				{
					creatMSG = "选择的三点不能为同一点，\n或者有任意两点相同。";
					return false;
				}
				YJKLine hyline = new YJKLine(startPnt, endPnt);
				hyline.MakeUnBound();
				if (hyline.IsPointOnCurveLine(onPnt))
				{
					creatMSG = "确定弧线的第三点，不能在起点与终点构成的直线上。";
					return false;
				}
				this.baseArc = this.doc.CreatYJKArc(startPnt, endPnt, onPnt);
				this.centerPnt = this.baseArc.Center;
				this.radius = this.baseArc.Radius;
				XYZ xyz = startPnt.Add(endPnt) / 2.0;
				if (xyz.IsAlmostEqualTo(this.centerPnt, 0.0001))
				{
					creatMSG = "选择的三点不能构成半圆，\n半圆时没有办法进行径向分割；\n请重新选择区域。";
					return false;
				}
				hyline = new YJKLine(xyz, this.centerPnt);
				hyline.MakeUnBound();
				YJKCurve hycurve = new YJKCurve(this.baseArc);
				this.arcPnt = hycurve.IntersectionPoint(hyline.Line);
				this.sideLine1 = this.doc.CreatYJKLine(startPnt, this.centerPnt, true);
				this.sideLine2 = this.doc.CreatYJKLine(endPnt, this.centerPnt, true);
				this.midLine = this.doc.CreatYJKLine(this.arcPnt, this.centerPnt, true);
			}
			catch (Exception ex)
			{
				creatMSG = ex.Message;
				result = false;
			}
			return result;
		}

		public bool CreatSector(XYZ startPnt, XYZ endPnt, XYZ onPnt, ref string creatMSG)
		{
			bool result = true;
			this.SetPointZValue(ref startPnt, this.GetActiveViewZeroLevle());
			this.SetPointZValue(ref endPnt, this.GetActiveViewZeroLevle());
			this.SetPointZValue(ref onPnt, this.GetActiveViewZeroLevle());
			this.sPoint = startPnt;
			this.ePoint = endPnt;
			SubTransaction subTransaction = new SubTransaction(this.doc);
			try
			{
				if (startPnt.IsAlmostEqualTo(endPnt, 0.001) || endPnt.IsAlmostEqualTo(onPnt, 0.001) || startPnt.IsAlmostEqualTo(onPnt, 0.001))
				{
					creatMSG = "选择的三点不能为同一点，\n或者有任意两点相同。";
					return false;
				}
				subTransaction.Start();
				YJKLine hyline = new YJKLine(startPnt, endPnt);
				hyline.MakeUnBound();
				if (hyline.IsPointOnCurveLine(onPnt))
				{
					creatMSG = "确定弧线的第三点，不能在起点与终点构成的直线上。";
					return false;
				}
				this.baseArc = this.doc.CreatYJKArc(startPnt, endPnt, onPnt);
				this.centerPnt = this.baseArc.Center;
				this.radius = this.baseArc.Radius;
				XYZ xyz = startPnt.Add(endPnt) / 2.0;
				if (xyz.IsAlmostEqualTo(this.centerPnt, 0.0001))
				{
					creatMSG = "选择的三点不能构成半圆，\n半圆时没有办法进行径向分割；\n请重新选择区域。";
					return false;
				}
				hyline = new YJKLine(xyz, this.centerPnt);
				hyline.MakeUnBound();
				YJKCurve hycurve = new YJKCurve(this.baseArc);
				this.arcCurve = this.doc.CreatHYModelCurve(hycurve.Curve);
				this.arcPnt = hycurve.IntersectionPoint(hyline.Line);
				this.sideLine1 = this.doc.CreatYJKLine(startPnt, this.centerPnt, true);
				this.radiusCurve1 = this.doc.CreatHYModelCurve(this.sideLine1);
				this.sideLine2 = this.doc.CreatYJKLine(endPnt, this.centerPnt, true);
				this.radiusCurve2 = this.doc.CreatHYModelCurve(this.sideLine2);
				this.midLine = this.doc.CreatYJKLine(this.arcPnt, this.centerPnt, true);
				subTransaction.Commit();
			}
			catch (Exception ex)
			{
				creatMSG = ex.Message;
				result = false;
			}
			finally
			{
				TransactionStatus status = subTransaction.GetStatus();
                if (3 != (int)status && (int)status == 1)
				{
					subTransaction.RollBack();
				}
			}
			return result;
		}

		public void SetPointZValue(ref XYZ point, double zValue = 0.0)
		{
			point = new XYZ(point.X, point.Y, zValue);
		}

		public double GetActiveViewZeroLevle()
		{
			return this.doc.ActiveView.GenLevel.Elevation;
		}

		public bool CheckPntInSector(XYZ point)
		{
			if (point.DistanceTo(this.CenterPnt) > this.Radius)
			{
				return false;
			}
			XYZ xyz = this.arcPnt.Subtract(this.CenterPnt);
			double num = this.sPoint.Subtract(this.CenterPnt).AngleTo(xyz);
			return point.Subtract(this.CenterPnt).AngleTo(xyz) <= num;
		}

		public Arc GetArcInSectorByPoint(XYZ point)
		{
			Arc result = null;
			double num = point.DistanceTo(this.centerPnt);
			if (num > 0.016404199475065617)
			{
				YJKCurve hycurve = new YJKCurve(this.doc.CreatYJKArc(this.centerPnt, num, 0.0, Math.PI*2, XYZ.BasisX, XYZ.BasisY));
				XYZ startPnt = hycurve.IntersectionPoint(this.sideLine1);
				XYZ endPnt = hycurve.IntersectionPoint(this.sideLine2);
				XYZ radianPnt = hycurve.IntersectionPoint(this.midLine);
				result = this.doc.CreatYJKArc(startPnt, endPnt, radianPnt);
			}
			return result;
		}

		public FamilySymbol GetSprinklerSymbol(int sprinklerId, string symbolName)
		{
			return new SpaceFamilyDataReader().GetFamilySymbolByIdSubTran(sprinklerId, "Sprinkler", symbolName, this.doc, BuiltInCategory.OST_Sprinklers);
		}

		public List<XYZ> GetArcLayPoints(XYZ saPnt, XYZ eaPnt, XYZ maPnt, int baseDis, int sideDis, double offset)
		{
			new List<XYZ>();
			return new YJKCurve(this.doc.CreatYJKArc(saPnt, eaPnt, maPnt)).GetLayLineXYZList(saPnt, (double)baseDis / 304.8, (double)sideDis / 304.8, offset, this.doc);
		}

		public List<XYZ> GetArcLayPoints(XYZ saPnt, XYZ eaPnt, XYZ maPnt, int num, double ratio, double offset)
		{
			new List<XYZ>();
			double num2 = this.doc.ActiveView.GenLevel.Elevation + offset;
			saPnt = new XYZ(saPnt.X, saPnt.Y, num2);
			eaPnt = new XYZ(eaPnt.X, eaPnt.Y, num2);
			maPnt = new XYZ(maPnt.X, maPnt.Y, num2);
			Arc arc = this.doc.CreatYJKArc(saPnt, eaPnt, maPnt);
			return this.GetPointOfDividedArc(num, ratio, 50, arc, saPnt);
		}

		public List<FamilyInstance> SectorLaySprinklers(List<XYZ> listPnt, FamilySymbol symbol)
		{
			List<FamilyInstance> list = new List<FamilyInstance>();
			ElementSet elementSet = new ConnectHelper().LayFamilyInstance(listPnt, symbol, this.doc.ActiveView.GenLevel, 0, this.doc);
			if (elementSet == null)
			{
				return null;
			}
			if (elementSet != null || elementSet.Size > 0)
			{
				foreach (object obj in elementSet)
				{
					Element element = (Element)obj;
					list.Add(element as FamilyInstance);
				}
			}
			return list;
		}

		public List<List<XYZ>> GetLayPoints(XYZ point, int maxRow, int maxCol, int minDistance, int maxSideRow, int maxSideCol, int disDivisor, double offSet)
		{
			int minSide = 200;
			new List<List<XYZ>>();
			List<Arc> list = new List<Arc>();
			List<Line> list2 = new List<Line>();
			XYZ intersectionByArcAndLine;
			if (point.IsAlmostEqualTo(this.centerPnt))
			{
				intersectionByArcAndLine = this.centerPnt;
			}
			else
			{
				Arc arcInSectorByPoint = this.GetArcInSectorByPoint(point);
				intersectionByArcAndLine = this.GetIntersectionByArcAndLine(arcInSectorByPoint);
			}
			foreach (XYZ point2 in this.GetPointOfDividedLine(maxRow, minDistance, maxSideRow, minSide, disDivisor, this.sPoint, intersectionByArcAndLine))
			{
				Arc arcInSectorByPoint = this.GetArcInSectorByPoint(point2);
				list.Add(arcInSectorByPoint);
			}
			Arc arc = this.baseArc;
			if (list != null && list.Count > 0)
			{
				arc = list[0];
			}
			foreach (XYZ point3 in this.GetPointOfDividedArc(maxCol, minDistance, maxSideCol, minSide, disDivisor, this.sPoint, arc))
			{
                XYZ pp = point3;

                this.SetPointZValue(ref pp, this.GetActiveViewZeroLevle());
                Line item = this.doc.CreatYJKLine(pp, this.centerPnt, true);
				list2.Add(item);
			}
			return this.GetSprinklerLayPoints(list2, list, offSet);
		}

		public List<List<XYZ>> GetLayPoints(XYZ point, int rowNum, int colNum, double ratios, int disDivisor, double offSet)
		{
			new List<List<XYZ>>();
			List<Arc> list = new List<Arc>();
			List<Line> list2 = new List<Line>();
			XYZ intersectionByArcAndLine;
			if (point.IsAlmostEqualTo(this.centerPnt))
			{
				intersectionByArcAndLine = this.centerPnt;
			}
			else
			{
				Arc arcInSectorByPoint = this.GetArcInSectorByPoint(point);
				intersectionByArcAndLine = this.GetIntersectionByArcAndLine(arcInSectorByPoint);
			}
			foreach (XYZ point2 in this.GetPointOfDividedLine(rowNum, ratios, disDivisor, this.sPoint, intersectionByArcAndLine))
			{
				Arc arcInSectorByPoint = this.GetArcInSectorByPoint(point2);
				list.Add(arcInSectorByPoint);
			}
			Arc arc = this.baseArc;
			if (list != null && list.Count > 0)
			{
				arc = list[0];
			}
			foreach (XYZ point3 in this.GetPointOfDividedArc(colNum, ratios, disDivisor, arc, this.sPoint))
			{
                XYZ pp = point3;
                this.SetPointZValue(ref pp, this.GetActiveViewZeroLevle());
                Line item = this.doc.CreatYJKLine(pp, this.centerPnt, true);
				list2.Add(item);
			}
			return this.GetSprinklerLayPoints(list2, list, offSet);
		}

		private List<List<XYZ>> GetSprinklerLayPoints(List<Line> listLine, List<Arc> listArc, double offset)
		{
			List<List<XYZ>> list = new List<List<XYZ>>();
			if (listLine != null && listLine.Count > 0 && listArc != null && listArc.Count > 0)
			{
				foreach (Line otherCurve in listLine)
				{
					List<XYZ> list2 = new List<XYZ>();
					foreach (Arc curve in listArc)
					{
						XYZ xyz = new YJKCurve(curve).IntersectionPoint(otherCurve);
						xyz = new XYZ(xyz.X, xyz.Y, offset);
						list2.Add(xyz);
					}
					list.Add(list2);
				}
			}
			return list;
		}

		private XYZ GetIntersectionByArcAndLine(Arc arc)
		{
			return new YJKCurve(arc).IntersectionPoint(this.sideLine1);
		}

		private List<Arc> GetRowArc(double rowDistance, double rowSideDis, double offSet)
		{
			List<Arc> list = new List<Arc>();
			foreach (XYZ point in new YJKLine(this.sideLine1).GetLayLineXYZList(this.sPoint, rowDistance, rowSideDis, offSet))
			{
				Arc arcInSectorByPoint = this.GetArcInSectorByPoint(point);
				if (arcInSectorByPoint != null)
				{
					list.Add(arcInSectorByPoint);
				}
			}
			return list;
		}

		private List<XYZ> GetArcInPoint(double colDistance, double colSideDis, double offSet)
		{
			List<XYZ> list = new List<XYZ>();
			list = new YJKCurve(this.baseArc).GetLayLineXYZList(this.sPoint, colDistance, colSideDis, offSet);
			foreach (XYZ point in list)
			{
				this.doc.CreatYJKLine(point, this.centerPnt, true);
			}
			return list;
		}

		public List<XYZ> GetPointOfDividedLine(int rowNum, double ratios, int divisor, XYZ sLinePnt, XYZ eLinePnt)
		{
			List<XYZ> list = new List<XYZ>();
			if (rowNum < 1 || ratios < -0.0001)
			{
				throw new Exception("布置参数有错误");
			}
			if (rowNum == 1)
			{
				list.Add(sLinePnt.Add(eLinePnt) / 2.0);
			}
			else
			{
				XYZ xyz = (eLinePnt - sLinePnt).Normalize();
				double num = sLinePnt.DistanceTo(eLinePnt) * 304.8 / ((double)(rowNum - 1) + 2.0 * ratios);
				num -= num % (double)divisor;
				double num2 = num * ratios;
				num2 += (double)divisor - num2 % (double)divisor;
				for (int i = 0; i < rowNum; i++)
				{
					list.Add(this.sPoint + (num2 + num * (double)i) / 304.8 * xyz);
				}
			}
			return list;
		}

		public List<XYZ> GetPointOfDividedArc(int colNum, double ratios, int divisor, Arc arc, XYZ sArcPnt)
		{
			List<XYZ> list = new List<XYZ>();
			if (colNum < 1 || ratios < -0.0001)
			{
				throw new Exception("布置参数有错误");
			}
			double num = arc.Length * 304.8;
			if (colNum == 1)
			{
				list.Add(this.GetArcMiddlePoint(arc));
			}
			else
			{
				double num2 = num / ((double)(colNum - 1) + 2.0 * ratios);
				double num3 = num / ((double)(colNum - 1) + 2.0 * ratios);
				num2 = this.GetChordLengthByArc(arc.Radius, num2 / 304.8);
				num3 = this.GetChordLengthByArc(arc.Radius, num3 / 304.8);
				num2 -= num2 % (double)divisor;
				double num4 = num2 * ratios;
				double num5 = num3 * ratios;
				num4 += (double)divisor - num4 % (double)divisor;
				YJKCurve hycurve = new YJKCurve(arc);
				list = hycurve.GetLayLineXYZList(sArcPnt, num2 / 304.8, num4 / 304.8, sArcPnt.Z, this.doc);
				if (list.Count != colNum)
				{
					list = hycurve.GetLayLineXYZList(sArcPnt, num3 / 304.8, num5 / 304.8, sArcPnt.Z, this.doc);
				}
			}
			return list;
		}

		public List<XYZ> GetPointOfDividedLine(int maxDis, int minDis, int maxSide, int minSide, int disDivisor, XYZ sLinePnt, XYZ eLinePnt)
		{
			List<XYZ> list = new List<XYZ>();
			YJKLine hyline = new YJKLine(sLinePnt, eLinePnt);
			if (hyline.Line == null)
			{
				return list;
			}
			double num = hyline.Line.Length * 304.8;
			int i = Convert.ToInt32((num - num % (double)maxDis) / (double)maxDis);
			int num2 = maxDis - maxDis % disDivisor;
			int num3 = minDis + (disDivisor - minDis % disDivisor);
			int num4 = 0;
			int num5 = 0;
			if (i == 0)
			{
				list.Add(sLinePnt.Add(eLinePnt) / 2.0);
				return list;
			}
			while (i > 0)
			{
				for (int j = num2; j >= num3; j -= disDivisor)
				{
					if (num - (double)(i * j) >= (double)(2 * maxSide))
					{
						i = 0;
						break;
					}
					num4 = i;
					num5 = j;
				}
				if (i == 1)
				{
					break;
				}
				i--;
			}
			XYZ xyz = eLinePnt.Subtract(sLinePnt).Normalize();
			double num6 = (num - (double)(num4 * num5)) / 2.0;
			num6 += (double)disDivisor - num6 % (double)disDivisor;
			for (int k = 0; k <= num4; k++)
			{
				XYZ item = this.sPoint + num6 / 304.8 * xyz + (double)(k * num5) / 304.8 * xyz;
				list.Add(item);
			}
			return list;
		}

		public List<XYZ> GetPointOfDividedArc(int maxDis, int minDis, int maxSide, int minSide, int disDivisor, XYZ sArcPnt, Arc arc)
		{
			List<XYZ> list = new List<XYZ>();
			double num = arc.Length * 304.8;
			double arcLengthByChord = this.GetArcLengthByChord(arc.Radius, (double)maxDis / 304.8);
			double arcLengthByChord2 = this.GetArcLengthByChord(arc.Radius, (double)minDis / 304.8);
			double arcLengthByChord3 = this.GetArcLengthByChord(arc.Radius, (double)maxSide / 304.8);
			this.GetArcLengthByChord(arc.Radius, (double)minSide / 304.8);
			double arcLengthByChord4 = this.GetArcLengthByChord(arc.Radius, (double)disDivisor / 304.8);
			double num2 = arcLengthByChord;
			double num3 = arcLengthByChord2;
			int num4 = 0;
			double num5 = 0.0;
			int i = Convert.ToInt32(Math.Floor(num / arcLengthByChord));
			if (i == 0)
			{
				list.Add(this.GetArcMiddlePoint(arc));
				return list;
			}
			while (i > 0)
			{
				for (double num6 = num2; num6 >= num3; num6 -= arcLengthByChord4)
				{
					if (num - (double)i * num6 >= 2.0 * arcLengthByChord3)
					{
						i = 0;
						break;
					}
					num4 = i;
					num5 = num6;
				}
				if (i == 1)
				{
					break;
				}
				i--;
			}
			double num7 = (num - (double)num4 * num5) / 2.0;
			double num8 = this.GetChordLengthByArc(arc.Radius, num7 / 304.8);
			double num9 = this.GetChordLengthByArc(arc.Radius, num5 / 304.8);
			num9 -= num9 % (double)disDivisor;
			num8 += (double)disDivisor - num9 % (double)disDivisor;
			num8 = Math.Floor(num8);
			num8 -= num8 % (double)disDivisor;
			num9 = Math.Floor(num9);
			num9 += (double)disDivisor - num9 % (double)disDivisor;
			if (num9 > (double)maxDis)
			{
				num9 -= (double)disDivisor;
			}
			return new YJKCurve(arc).GetLayLineXYZList(sArcPnt, num9 / 304.8, num8 / 304.8, sArcPnt.Z, this.doc);
		}

		private bool JudgePntInArc(Arc arc)
		{
			bool flag = false;
			YJKCurve hycurve = new YJKCurve(arc);
			XYZ startPoint = hycurve.StartPoint;
			XYZ endPoint = hycurve.EndPoint;
			XYZ center = arc.Center;
			XYZ xyz = startPoint.Add(endPoint) / 2.0;
			YJKLine hyline = new YJKLine(center, xyz);
			hyline.MakeUnBound();
			return hycurve.IntersectionPoint(hyline.Line).DistanceTo(xyz) > arc.Radius || flag;
		}

		private double GetArcLengthByChord(Arc arc, double chordLength)
		{
			double num = Math.Asin(chordLength / (2.0 * arc.Radius)) * 2.0;
			num = num * 180.0 / Math.PI;
			if (this.JudgePntInArc(arc))
			{
				num = 360.0 - num;
			}
			return 957.557440814169 * arc.Radius * num / 180.0;
		}

		private double GetArcLengthByChord(double radius, double chordLength)
		{
			double num = Math.Asin(chordLength / (2.0 * radius)) * 2.0;
			if (num.ToString().Equals("非数字"))
			{
				throw new Exception("选择区域太小,无法计算布置点！");
			}
			num = num * 180.0 / Math.PI;
			return 957.557440814169 * radius * num / 180.0;
		}

		private double GetChordLengthByArc(double radius, double arcLength)
		{
			double num = arcLength * 180.0 / (Math.PI * radius);
			num = Math.PI * num / 180.0;
			return radius * Math.Sin(num / 2.0) * 2.0 * 304.8;
		}

		private XYZ GetArcMiddlePoint(Arc arc)
		{
			YJKCurve hycurve = new YJKCurve(arc);
			XYZ startPoint = hycurve.StartPoint;
			XYZ endPoint = hycurve.EndPoint;
			YJKLine hyline = new YJKLine(startPoint.Subtract(endPoint) / 2.0, arc.Center);
			hyline.MakeUnBound();
			return hycurve.IntersectionPoint(hyline.Line);
		}

		public ModelCurve ArcCurve
		{
			get
			{
				return this.arcCurve;
			}
			set
			{
				this.arcCurve = value;
			}
		}

		public ModelCurve RadiusCurve1
		{
			get
			{
				return this.radiusCurve1;
			}
			set
			{
				this.radiusCurve1 = value;
			}
		}

		public ModelCurve RadiusCurve2
		{
			get
			{
				return this.radiusCurve2;
			}
			set
			{
				this.radiusCurve2 = value;
			}
		}

		public XYZ CenterPnt
		{
			get
			{
				return this.centerPnt;
			}
			set
			{
				this.centerPnt = value;
			}
		}

		public double Radius
		{
			get
			{
				return this.radius;
			}
			set
			{
				this.radius = value;
			}
		}

		private Document doc;

		private XYZ centerPnt;

		public XYZ sPoint;

		public XYZ ePoint;

		public XYZ onPoint;

		public XYZ unPoint;

		private double radius;

		private Arc baseArc;

		private ModelCurve arcCurve;

		private ModelCurve radiusCurve1;

		private ModelCurve radiusCurve2;

		private XYZ arcPnt;

		private Line sideLine1;

		private Line sideLine2;

		private Line midLine;
	}
}
